﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

namespace myking
{
    public class getrich
    {
        #region api声明
        [DllImport("User32.DLL")]
        public static extern int SendMessage(
            IntPtr hWnd, uint Msg, int wParam, int lParam);
        public delegate bool WNDENUMPROC(
            IntPtr hwnd, int lParam);
        [DllImport("user32.dll")]
        public static extern int EnumWindows(
            WNDENUMPROC lpEnumFunc, int lParam);
        [DllImport("user32.dll")]
        public static extern int EnumChildWindows(
            IntPtr hWndParent, WNDENUMPROC lpEnumFunc, int lParam);
        [DllImport("user32.dll")]
        public static extern int GetWindowText(
            IntPtr hWnd, StringBuilder lpString, int nMaxCount);
        [DllImport("user32.dll")]
        public static extern int GetClassName(
            IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
        [DllImport("user32.dll")]
        public static extern bool IsWindow(IntPtr hWnd);
        [DllImport("user32.dll")]
        public static extern bool IsWindowVisible(IntPtr hWnd);
        [DllImport("user32.DLL")]
        public static extern IntPtr FindWindowEx(
            IntPtr hwndParent, IntPtr hwndChildAfter,
            string lpszClass, string lpszWindow);
        [DllImport("user32.dll")]
        public static extern uint GetWindowThreadProcessId(
            IntPtr hWnd, out uint dwProcessId);
        [DllImport("psapi.dll")]
        public static extern uint GetModuleBaseName(
            IntPtr hProcess, IntPtr hModule,
            StringBuilder lpBaseName, uint nSize);
        public const uint PROCESS_VM_OPERATION = 0x0008;
        public const uint PROCESS_VM_READ = 0x0010;
        public const uint PROCESS_VM_WRITE = 0x0020;
        public const uint PROCESS_QUERY_INFORMATION = 0x0400;
        [DllImport("kernel32.dll")]
        public static extern IntPtr OpenProcess(
            uint dwDesiredAccess, bool bInheritHandle, uint dwProcessId);
        [DllImport("kernel32.dll")]
        public static extern bool CloseHandle(IntPtr handle);
        [DllImport("user32.dll")]
        public static extern int GetWindowLong(IntPtr hWnd, int nIndex);
        public const int GWL_STYLE = -16;
        public const int ES_READONLY = 0x800;
        public const uint MEM_COMMIT = 0x1000;
        public const uint MEM_RELEASE = 0x8000;
        public const uint MEM_RESERVE = 0x2000;
        public const uint PAGE_READWRITE = 4;
        [DllImport("kernel32.dll")]
        public static extern IntPtr VirtualAllocEx(
            IntPtr hProcess, IntPtr lpAddress, uint dwSize,
            uint flAllocationType, uint flProtect);
        [DllImport("kernel32.dll")]
        public static extern bool VirtualFreeEx(
            IntPtr hProcess, IntPtr lpAddress,
            uint dwSize, uint dwFreeType);
        [DllImport("kernel32.dll")]
        public static extern bool WriteProcessMemory(
            IntPtr hProcess, IntPtr lpBaseAddress, IntPtr lpBuffer,
            int nSize, ref uint vNumberOfBytesRead);
        [DllImport("kernel32.dll")]
        public static extern bool ReadProcessMemory(
            IntPtr hProcess, IntPtr lpBaseAddress, IntPtr lpBuffer,
            int nSize, ref uint vNumberOfBytesRead);
        private IntPtr richHandle;
        #endregion

        public string GetProcessName(uint AProcessId)
        {
            StringBuilder vBuffer = new StringBuilder(256);
            IntPtr vProcess = OpenProcess(
                PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
                false, AProcessId);
            try
            {
                if (GetModuleBaseName(
                    vProcess, IntPtr.Zero, vBuffer,
                    (uint)vBuffer.Capacity) > 0)
                {
                    return vBuffer.ToString();
                }
                else
                    return string.Empty;
            }
            finally
            {
                CloseHandle(vProcess);
            }
        }

        public bool EnumChild(IntPtr hwnd, int lParam)
        {
            if (!IsWindowVisible(hwnd))
                return true; // 不可见  

            StringBuilder vBuffer = new StringBuilder(256);
            GetClassName(hwnd, vBuffer, vBuffer.Capacity);

            if (vBuffer.ToString().ToLower() == "richedit20a")
            {
                if ((GetWindowLong(hwnd, GWL_STYLE) & ES_READONLY)
                    != ES_READONLY) // 非只读
                {
                    richHandle = hwnd;
                    return false;
                }
            }
            return true;
        }

        public bool EnumFunc(IntPtr hwnd, int lParam)
        {
            if (!IsWindowVisible(hwnd))
                return true; // 不可见  

            StringBuilder vBuffer = new StringBuilder(256);
            GetClassName(hwnd, vBuffer, vBuffer.Capacity);

            if (vBuffer.ToString() == "#32770")
            {
                uint vProcessId;
                GetWindowThreadProcessId(hwnd, out vProcessId);
                if (GetProcessName(vProcessId).ToLower() == "qq.exe")
                {
                    GetWindowText(hwnd, vBuffer, vBuffer.Capacity);
                    // 标题中含"聊天中" 
                    if (vBuffer.ToString().IndexOf("聊天中") >= 0)
                    {
                        EnumChildWindows(hwnd, @EnumChild, lParam);
                        return false;
                    }
                }
            }
            return true;
        }


        [StructLayout(LayoutKind.Sequential)]
        public struct GETTEXTLENGTHEX
        {
            public uint flags;
            public uint codepage;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct GETTEXTEX
        {
            public int cb;
            public int flags;
            public int codepage;
            public IntPtr lpDefaultChar;
            public IntPtr lpUsedDefChar;
        }

        public const int GTL_DEFAULT = 0;
        public const int GT_DEFAULT = 0;
        public const int WM_USER = 0x0400;
        public const int EM_GETTEXTEX = WM_USER + 94;
        public const int EM_GETTEXTLENGTHEX = WM_USER + 95;

        public string Process_ReadRichEditText(IntPtr AHandle)
        {
            if (!IsWindow(AHandle))
                return string.Empty;

            string vReturn = string.Empty;
            uint vProcessId;
            IntPtr vPointer = IntPtr.Zero;
            IntPtr vAddress = IntPtr.Zero;
            int L = 0;

            GetWindowThreadProcessId(AHandle, out vProcessId);
            IntPtr vProcess = OpenProcess(
                PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE,
                false, vProcessId);
            try
            {
                uint vNumberOfBytesRead = 0;
                    vPointer = VirtualAllocEx(
                    vProcess, IntPtr.Zero, 0x1000,
                    MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);

                GETTEXTLENGTHEX vGetTextLengthEx = new GETTEXTLENGTHEX();
                vGetTextLengthEx.flags = GTL_DEFAULT;
                vGetTextLengthEx.codepage = 1200; // Unicode   
                vAddress = Marshal.AllocCoTaskMem(
                    Marshal.SizeOf(vGetTextLengthEx));
                Marshal.StructureToPtr(vGetTextLengthEx, vAddress, false);
                WriteProcessMemory(vProcess, vPointer, vAddress,
                                   Marshal.SizeOf(vGetTextLengthEx),
                                   ref vNumberOfBytesRead);
                Marshal.FreeCoTaskMem(vAddress);

                L = SendMessage(
                    AHandle, EM_GETTEXTLENGTHEX,
                    (int)vPointer, 0);
                VirtualFreeEx(vProcess, vPointer, 0, MEM_RELEASE);

                if (L <= 0)
                    return vReturn;

                GETTEXTEX vGetTextEx = new GETTEXTEX();
                vGetTextEx.cb = L * 2 + 2;
                vGetTextEx.flags = GT_DEFAULT;
                vGetTextEx.codepage = 1200; // Unicode      
                vGetTextEx.lpDefaultChar = IntPtr.Zero;
                vGetTextEx.lpUsedDefChar = IntPtr.Zero;

                vPointer = VirtualAllocEx(vProcess, IntPtr.Zero,
                          (uint)(Marshal.SizeOf(vGetTextEx) + L * 2 + 2),
                          MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
                vAddress = Marshal.AllocCoTaskMem(Marshal.SizeOf(vGetTextEx));

                Marshal.StructureToPtr(
                    vGetTextEx, vAddress, false);
                WriteProcessMemory(vProcess, vPointer, vAddress,
                                   Marshal.SizeOf(vGetTextEx),
                                   ref vNumberOfBytesRead);
                Marshal.FreeCoTaskMem(vAddress);
                SendMessage(AHandle, EM_GETTEXTEX, (int)vPointer,
                            (int)vPointer + Marshal.SizeOf(vGetTextEx));
                vAddress = Marshal.AllocCoTaskMem(L * 2);
                ReadProcessMemory(vProcess,
                  (IntPtr)((int)vPointer + Marshal.SizeOf(vGetTextEx)),
                  vAddress, L * 2, ref vNumberOfBytesRead);
                //vReturn = Marshal.PtrToStringUni(vAddress, L * 2);
                vReturn = Marshal.PtrToStringUni(vAddress, L);
                Marshal.FreeCoTaskMem(vAddress);
                VirtualFreeEx(vProcess, vPointer, 0, MEM_RELEASE);

                //try { vReturn = Marshal.PtrToStringUni(vAddress, L * 2); }
                //catch (Exception ex) { }
                //Marshal.FreeCoTaskMem(vAddress);
                //VirtualFreeEx(vProcess, vPointer, 0, MEM_RELEASE);

            }
            //catch (Exception e)
            //{

            //}
            finally
            {
                CloseHandle(vProcess);
            }
            CloseHandle(vProcess);
            return vReturn;
        }

        public string getrichtext()
        {
            richHandle = IntPtr.Zero;
            EnumWindows(EnumFunc, 0);
            if (richHandle == IntPtr.Zero)
                return "";
            return Process_ReadRichEditText(richHandle);
        }

    }
}
